package mse.tx.arch.pipe.filters;

import java.io.IOException;
import java.util.Calendar;

import mse.tx.arch.pipe.framework.FilterFramework;

public class MergeFilter extends FilterFramework {
	public MergeFilter() {
		addInputPortByName("input1");
		addInputPortByName("input2");
		addOutputPortByName("output");
	}

	public void run() {
		boolean endOfInput1 = false;
		boolean endOfInput2 = false;
		
		
		Calendar time1 = Calendar.getInstance();
		Calendar time2 = Calendar.getInstance();
		
		int id = 0;
		long measurement = 0;
		
		try {
			id = readID("input1");
			measurement = readMeasurement("input1");
			time1.setTimeInMillis(measurement);
		} catch (Exception e) {
			endOfInput1 = true;
		}

		try {
			id = readID("input1");
			measurement = readMeasurement("input1");
			time2.setTimeInMillis(measurement);
		} catch (Exception e) {
			endOfInput2 = true;
		}
		
		try {
			while (!(endOfInput1 && endOfInput2)) {
				
				if ((time1.before(time2) || endOfInput2) && !endOfInput1) {
					writeID(0);
					writeMeasurement(time1.getTimeInMillis());
					try {
						id = readID("input1");
						measurement = readMeasurement("input1");
					} catch (Exception e) {
						endOfInput1 = true;
					}
					while (id != 0) {
						writeID(id);
						writeMeasurement(measurement);
						try {
							id = readID("input1");
							measurement = readMeasurement("input1");
						} catch (Exception e) {
							endOfInput1 = true;
							break;
						}
					}
					time1.setTimeInMillis(measurement);
				}
				
				if ((time2.before(time1) || endOfInput1) && !endOfInput2) {
					writeID(0);
					writeMeasurement(time2.getTimeInMillis());
					try {
						id = readID("input2");
						measurement = readMeasurement("input2");
					} catch (Exception e) {
						endOfInput2 = true;
					}
					while (id != 0) {
						writeID(id);
						writeMeasurement(measurement);
						try {
							id = readID("input2");
							measurement = readMeasurement("input2");
						} catch (Exception e) {
							endOfInput1 = true;
							break;
						}
					}
					time2.setTimeInMillis(measurement);
				}
			}
		} catch (Exception e) {
			System.err.print("\n cannot write data to output port! \n");
		}
	}

	private int readID(String inputPortName) throws IOException,
			EndOfStreamException {
		int IdLength = 4; // This is the length of IDs in the byte stream

		int id = 0;

		byte databyte;

		for (int i = 0; i < IdLength; i++) {
			databyte = readFilterInputPort(inputPortName);

			id = id | (databyte & 0xFF);

			if (i != IdLength - 1) {
				id = id << 8;
			}
		}
		return id;
	}

	private long readMeasurement(String inputPortName) throws IOException,
			EndOfStreamException {
		int MeasurementLength = 8;

		long measurement = 0;

		byte databyte;

		for (int i = 0; i < MeasurementLength; i++) {
			databyte = readFilterInputPort(inputPortName);
			measurement = measurement | (databyte & 0xFF);
			if (i != MeasurementLength - 1) {
				measurement = measurement << 8;
			}
		}

		return measurement;
	}

	private void writeID(int id) throws IOException {
		int IdLength = 4;

		byte databyte;

		for (int i = IdLength; i > 0; --i) {

			databyte = (byte) (id >> ((i - 1) * 8) & 0xFF);

			writeFilterOutputPort("output", databyte);
		}
	}

	private void writeMeasurement(long measurement) throws IOException {
		int MeasurementLength = 8;

		byte databyte;

		for (int i = MeasurementLength; i > 0; --i) {

			databyte = (byte) (measurement >> ((i - 1) * 8) & 0xFF);

			writeFilterOutputPort("output", databyte);
		}
	}
}
